package com.gupaoedu.springframework.mvcframework.webmvc;

import com.gupaoedu.springframework.mvcframework.annotation.MyController;
import com.gupaoedu.springframework.mvcframework.annotation.MyRequestMapping;
import com.gupaoedu.springframework.mvcframework.context.MyApplicationContext;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * projectName: my-springframwork
 * packageName: com.gupaoedu.springframework.mvcframework.webmvc
 * Created: 2019/4/15.
 * Auther: baifc
 * Description:
 */
public class MyDispatchServlet extends HttpServlet {

    private static final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";

    private MyApplicationContext applicationContext;

    private List<MyHandlerMapping> handlerMappings = new ArrayList<>();

    private Map<MyHandlerMapping, MyHandlerAdapter> handleAdapterMap = new HashMap<>();

    private List<MyViewResolver> viewResolvers = new ArrayList<>();

    @Override
    public void init(ServletConfig config) {
        applicationContext = new MyApplicationContext(config.getInitParameter(CONTEXT_CONFIG_LOCATION));

        try {
            initStrategies(applicationContext);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initStrategies(MyApplicationContext context) throws Exception {

        //多文件上传的组件
        initMultipartResolver(context);
        //初始化本地语言环境
        initLocaleResolver(context);
        //初始化模板处理器
        initThemeResolver(context);


        //handlerMapping，必须实现
        initHandlerMappings(context);
        //初始化参数适配器，必须实现
        initHandlerAdapters(context);
        //初始化异常拦截器
        initHandlerExceptionResolvers(context);

        //初始化视图预处理器
        initRequestToViewNameTranslator(context);


        //初始化视图转换器，必须实现
        initViewResolvers(context);

        //参数缓存器
        initFlashMapManager(context);
    }

    private void initMultipartResolver(MyApplicationContext context) {
    }

    private void initLocaleResolver(MyApplicationContext context) {
    }

    private void initThemeResolver(MyApplicationContext context) {
    }

    private void initHandlerMappings(MyApplicationContext context) throws Exception {

        String[] beanNames = context.getBeanDefinitionNames();

        for (String beanName : beanNames) {
             Class<?> clazz = Class.forName(beanName);

             Object controller = clazz.newInstance();
             if (!clazz.isAnnotationPresent(MyController.class)) {
                 continue;
             }

             String baseUrl = "";

             if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
                 MyRequestMapping baseMapping = clazz.getAnnotation(MyRequestMapping.class);
                 baseUrl = baseMapping.value();
             }

             Method[] methods = clazz.getMethods();

             for (Method method : methods) {
                 if (!method.isAnnotationPresent(MyRequestMapping.class)) {
                     continue;
                 }
                 MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class);

                 String reqUrl = requestMapping.value();

                 String regex = ("/" + baseUrl + "/" + reqUrl.replaceAll("\\*", ".*")).replaceAll("/+", "/");

                 Pattern pattern = Pattern.compile(regex);

                 handlerMappings.add(new MyHandlerMapping(pattern, controller, method));
             }
        }
    }

    private void initHandlerAdapters(MyApplicationContext context) {
        for (MyHandlerMapping handlerMapping : handlerMappings) {
            handleAdapterMap.put(handlerMapping, new MyHandlerAdapter());
        }
    }

    private void initHandlerExceptionResolvers(MyApplicationContext context) {
    }

    private void initRequestToViewNameTranslator(MyApplicationContext context) {
    }

    private void initViewResolvers(MyApplicationContext context) {
        String templateRoot = context.getConfig().getProperty("templateRoot");

        String templateDir = this.getClass().getClassLoader().getResource(templateRoot).getFile();

        File templateFile = new File(templateDir);

        for (File file : templateFile.listFiles()) {
            viewResolvers.add(new MyViewResolver(templateRoot));
        }

    }

    private void initFlashMapManager(MyApplicationContext context) {
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try{
            this.doDispatch(req,resp);
        }catch(Exception e){
            resp.getWriter().write("500 Exception,Details:\r\n" + Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]", "").replaceAll(",\\s", "\r\n"));
            e.printStackTrace();
//            new GPModelAndView("500");

        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //1、通过从request中拿到URL，去匹配一个HandlerMapping
        MyHandlerMapping handler = getHandler(req);

        if(handler == null){
            // TODO 404
            return;
        }

        //2、准备调用前的参数
        MyHandlerAdapter ha = getHandlerAdapter(handler);

        //3、真正的调用方法,返回ModelAndView存储了要传页面上值，和页面模板的名称
        MyModelAndView modelAndView = ha.handle(req, resp, handler);

        //这一步才是真正的输出
        processDispatchResult(req, resp, modelAndView);
    }

    private MyHandlerMapping getHandler(HttpServletRequest req){
        if (this.handlerMappings.isEmpty()) {
            return null;
        }

        String url = req.getRequestURI();
        String contextPath = req.getContextPath();

        url = url.replace(contextPath, "").replaceAll("/+", "/");

        for (MyHandlerMapping handler : handlerMappings) {
            Matcher matcher = handler.getPattern().matcher(url);

            if (!matcher.matches()) {
                continue;
            }
            return handler;
        }

        return null;
    }

    public MyHandlerAdapter getHandlerAdapter(MyHandlerMapping handler) {
        if (handleAdapterMap.isEmpty()) {
            return null;
        }

        MyHandlerAdapter ha = handleAdapterMap.get(handler);

        if (ha.supports(handler)) {
            return ha;
        }
        return null;
    }

    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, MyModelAndView mv) throws Exception{
        //把给我的ModleAndView变成一个HTML、OuputStream、json、freemark、veolcity
        //ContextType
        if(null == mv){return;}

        //如果ModelAndView不为null，怎么办？
        if(this.viewResolvers.isEmpty()){return;}

        for (MyViewResolver viewResolver : this.viewResolvers) {
//            MyView view = viewResolver.resolveViewName(mv.getViewName(),null);
//            view.render(mv.getModel(),req,resp);
            return;
        }


    }
}
